﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Windows.Media.Imaging;
using System.Windows.Printing;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using IssueVision.Data.Web;
using IssueVision.Common;
using MVVMPlugin;

namespace IssueVision.ViewModel
{
    [ExportPlugin(ViewModelTypes.BugReportViewModel, PluginType.ViewModel)]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class BugReportViewModel : ViewModelBase
    {
        #region "Private Data Members"
        private IIssueVisionModel _issueVisionModel;
        private ReportPrintout _reportPrintOut;
        private int _printedItems;
        #endregion "Private Data Members"

        #region "Constructor"
        public BugReportViewModel()
        {
            _issueVisionModel = PluginCatalogService.Container.GetExportedValue<IIssueVisionModel>();

            // set up event handling
            _issueVisionModel.GetAllUnresolvedIssuesComplete += _issueVisionModel_GetAllUnresolvedIssuesComplete;
            _issueVisionModel.GetActiveBugCountByMonthComplete += _issueVisionModel_GetActiveBugCountByMonthComplete;
            _issueVisionModel.GetResolvedBugCountByMonthComplete += _issueVisionModel_GetResolvedBugCountByMonthComplete;
            _issueVisionModel.GetActiveBugCountByPriorityComplete += _issueVisionModel_GetActiveBugCountByPriorityComplete;
            _issueVisionModel.PropertyChanged += _issueVisionModel_PropertyChanged;

            // load all issues
            _issueVisionModel.GetAllUnresolvedIssuesAsync();
            _issueVisionModel.GetActiveBugCountByMonthAsync(6);
            _issueVisionModel.GetResolvedBugCountByMonthAsync(6);
            _issueVisionModel.GetActiveBugCountByPriorityAsync();
        }
        #endregion "Constructor"

        #region "ICleanup interface implementation"
        public override void Cleanup()
        {
            if (_issueVisionModel != null)
            {
                // unregister all events
                _issueVisionModel.GetAllUnresolvedIssuesComplete -= _issueVisionModel_GetAllUnresolvedIssuesComplete;
                _issueVisionModel.GetActiveBugCountByMonthComplete -= _issueVisionModel_GetActiveBugCountByMonthComplete;
                _issueVisionModel.GetResolvedBugCountByMonthComplete -= _issueVisionModel_GetResolvedBugCountByMonthComplete;
                _issueVisionModel.GetActiveBugCountByPriorityComplete -= _issueVisionModel_GetActiveBugCountByPriorityComplete;
                _issueVisionModel.PropertyChanged -= _issueVisionModel_PropertyChanged;
                _issueVisionModel = null;
            }
            // set properties back to null
            AllIssues = null;
            ActiveBugCountByMonth = null;
            ResolvedBugCountByMonth = null;
            ActiveBugCountByPriority = null;
            // unregister any messages for this ViewModel
            base.Cleanup();
        }
        #endregion "ICleanup interface implementation"

        #region "Public Properties"

        private IEnumerable<Issue> _allIssues;

        public IEnumerable<Issue> AllIssues
        {
            get { return _allIssues; }
            private set
            {
                if (!ReferenceEquals(_allIssues, value))
                {
                    _allIssues = value;
                    RaisePropertyChanged("AllIssues");
                }
            }
        }

        private IEnumerable<BugCountByMonth> _activeBugCountByMonth;

        public IEnumerable<BugCountByMonth> ActiveBugCountByMonth
        {
            get { return _activeBugCountByMonth; }
            private set
            {
                if (!ReferenceEquals(_activeBugCountByMonth, value))
                {
                    _activeBugCountByMonth = value;
                    RaisePropertyChanged("ActiveBugCountByMonth");
                }
            }
        }

        private IEnumerable<BugCountByMonth> _resolvedBugCountByMonth;

        public IEnumerable<BugCountByMonth> ResolvedBugCountByMonth
        {
            get { return _resolvedBugCountByMonth; }
            private set
            {
                if (!ReferenceEquals(_resolvedBugCountByMonth, value))
                {
                    _resolvedBugCountByMonth = value;
                    RaisePropertyChanged("ResolvedBugCountByMonth");
                }
            }
        }

        private IEnumerable<BugCountByPriority> _activeBugCountByPriority;

        public IEnumerable<BugCountByPriority> ActiveBugCountByPriority
        {
            get { return _activeBugCountByPriority; }
            private set
            {
                if (!ReferenceEquals(_activeBugCountByPriority, value))
                {
                    _activeBugCountByPriority = value;
                    RaisePropertyChanged("ActiveBugCountByPriority");
                }
            }
        }

        #endregion "Public Properties"

        #region "Public Commands"

        private RelayCommand _printReportCommand;

        public RelayCommand PrintReportCommand
        {
            get
            {
                if (_printReportCommand == null)
                {
                    _printReportCommand = new RelayCommand(
                        OnPrintReportCommand,
                        () => (_issueVisionModel != null) && !(_issueVisionModel.IsBusy));
                }
                return _printReportCommand;
            }
        }

        private void OnPrintReportCommand()
        {
            try
            {
                var printDocument = new PrintDocument();
                printDocument.BeginPrint += printDocument_BeginPrint;
                printDocument.PrintPage += printDocument_PrintPage;
                printDocument.EndPrint += printDocument_EndPrint;
                printDocument.Print("IssueVision Bug Report");
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        #endregion "Public Commands"

        #region "Private Methods"

        private void _issueVisionModel_GetAllUnresolvedIssuesComplete(object sender, EntityResultsArgs<Issue> e)
        {
            if (!e.HasError)
            {
                AllIssues = e.Results
                    .OrderBy(g => g.Priority)
                    .ThenBy(g => g.Severity);
            }
            else
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(e.Error);
            }
        }

        private void _issueVisionModel_GetActiveBugCountByMonthComplete(object sender, InvokeOperationEventArgs e)
        {
            if (!e.HasError)
            {
                var bugCountList = new List<BugCountByMonth>();
                var bugCountStringArray = e.InvokeOp.Value as string[];
                if (bugCountStringArray != null)
                    bugCountList.AddRange(
                        bugCountStringArray.Select(
                        bugCount => new BugCountByMonth
                        {
                            Month = bugCount.Substring(0, 3) + bugCount.Substring(5, 2),
                            Count = Convert.ToInt32(bugCount.Substring(8))
                        }));
                ActiveBugCountByMonth = bugCountList.AsEnumerable();
            }
            else
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(e.Error);
            }
        }

        private void _issueVisionModel_GetResolvedBugCountByMonthComplete(object sender, InvokeOperationEventArgs e)
        {
            if (!e.HasError)
            {
                var bugCountList = new List<BugCountByMonth>();
                var bugCountStringArray = e.InvokeOp.Value as string[];
                if (bugCountStringArray != null)
                    bugCountList.AddRange(
                        bugCountStringArray.Select(
                        bugCount => new BugCountByMonth
                        {
                            Month = bugCount.Substring(0, 3) + bugCount.Substring(5, 2),
                            Count = Convert.ToInt32(bugCount.Substring(8))
                        }));
                ResolvedBugCountByMonth = bugCountList.AsEnumerable();
            }
            else
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(e.Error);
            }
        }

        private void _issueVisionModel_GetActiveBugCountByPriorityComplete(object sender, InvokeOperationEventArgs e)
        {
            if (!e.HasError)
            {
                var bugCountList = new List<BugCountByPriority>();
                var bugCountStringArray = e.InvokeOp.Value as string[];
                if (bugCountStringArray != null)
                    bugCountList.AddRange(
                        bugCountStringArray.Select(
                        bugCount => new BugCountByPriority
                        {
                            Priority = Convert.ToByte(bugCount.Substring(0, bugCount.IndexOf('/'))),
                            Count = Convert.ToInt32(bugCount.Substring(bugCount.IndexOf('/') + 1))
                        }));
                ActiveBugCountByPriority = bugCountList.AsEnumerable();
            }
            else
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(e.Error);
            }
        }

        private void _issueVisionModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName.Equals("IsBusy"))
            {
                PrintReportCommand.RaiseCanExecuteChanged();
            }
        }

        private void printDocument_BeginPrint(object sender, BeginPrintEventArgs e)
        {
            // get the charts currently in display as a WriteableBitmap
            WriteableBitmap writeableBitmap = null;
            var message = new NotificationMessageAction<WriteableBitmap>("Get Charts", s => writeableBitmap = s);
            AppMessages.GetChartsMessage.Send(message);

            _reportPrintOut = new ReportPrintout(writeableBitmap);
            _printedItems = 0;
        }

        private void printDocument_PrintPage(object sender, PrintPageEventArgs e)
        {
            if (_reportPrintOut != null)
            {
                e.PageVisual = _reportPrintOut;
                _reportPrintOut.Paginate(AllIssues, _printedItems, _printedItems == 0, e.PrintableArea);
                _printedItems += _reportPrintOut.NumItemsShown;
                e.HasMorePages = _printedItems < AllIssues.Count();
            }
            else
                e.HasMorePages = false;
        }

        private void printDocument_EndPrint(object sender, EndPrintEventArgs e)
        {
            _reportPrintOut = null;
        }

        #endregion "Private Methods"
    }
}